package org.brownflat.watergate.job;

import org.apache.commons.collections.MapUtils;
import org.apache.log4j.Logger;
import org.brownflat.watergate.domain.Branch;
import org.brownflat.watergate.service.BranchService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

import static java.lang.String.format;

/**
 * <p>&copy Rupert Jones 2012</p>
 *
 * @author rup
 */
@Component
public class InitiateScanRevisionsJob implements Runnable, BeanFactoryAware {

    private static final Logger LOG = Logger.getLogger(InitiateScanRevisionsJob.class);

    @Autowired
    private BranchService branchService;

    @Autowired
    private ThreadPoolTaskExecutor executor;

    private BeanFactory beanFactory;

    @SuppressWarnings("unchecked")
    private volatile Map<String, Future> runningTasks = MapUtils.synchronizedMap(new HashMap<String, Future>());

    @Override
    public synchronized void run() {
        LOG.debug("Looking for branches to initiate a scan...");

        Collection<Branch> branches = branchService.findAll();

        if(branches.isEmpty())  {
            LOG.debug("No branches found to scan.");
        }

        for(Branch branch : branches) {
            cleanHistory();

            if(!hasRunningTask(branch)) {
                ScanRevisionsJob scanRevisionsJob = (ScanRevisionsJob) beanFactory.getBean("scanRevisionsJob");
                scanRevisionsJob.setBranchId(branch.getId());
                Future runningTask = executor.submit(scanRevisionsJob);
                runningTasks.put(branch.getUniqueBranchKey(), runningTask);
            } else {
                LOG.warn(format("Will not initiate scan for branch [%s], already running. (%s)", branch.getName(), branch.getUniqueBranchKey()));
            }
        }
        LOG.debug("Finished looking for branches to scan.");
    }

    private boolean hasRunningTask(Branch branch) {
        return runningTasks.containsKey(branch.getUniqueBranchKey());
    }

    private void cleanHistory() {
        List<String> toClean = new ArrayList<String>();
        for(String taskId : runningTasks.keySet()) {
            Future task = runningTasks.get(taskId);
            if(task.isDone()) {
                toClean.add(taskId);
            }
        }

        for(String thisId : toClean) {
            runningTasks.remove(thisId);
        }
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}
